package com.bwton.msx.ccb.service.api.utils;

import android.util.Log;

import com.google.gson.Gson;

import org.apache.redefine.binary.Base64;
import org.apache.redefine.digest.DigestUtils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * AES加密工具
 * 采用AES/ECB/PKCS5Padding，128/256位加密
 *
 * @author Saintcy
 */

public class AESUtil {

    private static final String ALGORITHM_NAME_AES_ECB_PADDING = "AES/ECB/PKCS5Padding";
    private static final String ALGORITHM_NAME_AES_CBC_PADDING = "AES/CBC/PKCS5Padding";
    /**
     * 加密
     *
     * @param content  需要加密的内容
     * @param password 加密密码
     * @return
     */
    public static byte[] encrypt(String content, String password, int bits) {
        try {
            if (bits % 8 != 0) {
                throw new IllegalArgumentException("bits must be a multiple of 8");
            }
            // 创建密码器，AES默认是/ECB/PKCS5Padding
            Cipher cipher = getCipherByPwd(Cipher.ENCRYPT_MODE, password, bits);
            // 加密
            return cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
        } catch (Exception e) {
            System.err.println(e);
        }
        return null;
    }

    /**
     *
     * @param mode mode
     * @param password 密钥 新格式：AES/CBC:{iv},{password}
     * @param bits bits
     * @return Cipher
     * @throws Exception
     */
    private static Cipher getCipherByPwd(int mode, String password, int bits) throws Exception {
        if (password.contains("AES/CBC")) {
            // 兼容性代码 AES/CBC:{iv},{password}
            Cipher cipher = Cipher.getInstance(ALGORITHM_NAME_AES_CBC_PADDING);
            String[] pwdArray = password.split( ",");
            if (pwdArray != null && pwdArray.length > 0) {
                String[] algorithmArray = pwdArray[0].split(":");
                if (algorithmArray != null && algorithmArray.length > 0) {
                    Key key = new SecretKeySpec(pwdArray[1].getBytes(StandardCharsets.UTF_8), "AES");
                    cipher.init(mode, key, new IvParameterSpec(algorithmArray[1].getBytes(StandardCharsets.UTF_8)));
                }
            }
            return cipher;
        }
        //这里是128bit密钥，所以是 16 byte,如果是其它长度的 除以8 ，修改，这里简单演示一下
        byte[] newkey = new byte[bits / 8];
        for (int i = 0; i < newkey.length && i < password.getBytes().length; i++) {
            newkey[i] = password.getBytes()[i];
        }

        SecretKeySpec key = new SecretKeySpec(newkey, "AES");
        Cipher cipher = Cipher.getInstance(ALGORITHM_NAME_AES_ECB_PADDING);
        cipher.init(mode, key);
        return cipher;
    }

    /**
     * 默认128位加密
     *
     * @param content
     * @param password
     * @return
     */
    public static byte[] encrypt(String content, String password) {
        return encrypt(content, password, 128);
    }

    /**
     * 加密成base64表示的字符串
     *
     * @param content
     * @param password
     * @return
     */
    public static String encrypt256ToString(String content, String password) {

        return Base64.encodeBase64String(encrypt(content, password, 256));
    }

    /**
     * 加密成16进制字符串
     *
     * @param content  需要加密的内容
     * @param password 加密密码
     * @return
     */
    public static String encryp256tToHex(String content, String password) {
        return parseByte2HexStr(encrypt(content, password, 256));
    }

    /**
     * 加密成base64表示的字符串
     *
     * @param content
     * @param password
     * @return
     */
    public static String encryptToString(String content, String password) {

        return Base64.encodeBase64String(encrypt(content, password, 128));
    }

    /**
     * 加密成16进制字符串
     *
     * @param content  需要加密的内容
     * @param password 加密密码
     * @return
     */
    public static String encryptToHex(String content, String password) {
        return parseByte2HexStr(encrypt(content, password, 128));
    }

    /**
     * 解密
     *
     * @param content  待解密内容
     * @param password 解密密钥
     * @return
     */
    public static String decrypt(byte[] content, String password, int bits) {
        try {
            if (bits % 8 != 0) {
                throw new IllegalArgumentException("bits must be a multiple of 8");
            }
            // 创建密码器，AES默认是/ECB/PKCS5Padding
            Cipher cipher = getCipherByPwd(Cipher.DECRYPT_MODE, password, bits);
            // 加密
            return new String(cipher.doFinal(content));
        } catch (Exception e) {
            System.err.println(e);
        }
        return null;
    }

    /**
     * 默认128位解密
     *
     * @param content
     * @param password
     * @return
     */
    public static String decrypt(byte[] content, String password) {
        return decrypt(content, password, 128);
    }

    /**
     * 从base64标示的加密字符串中解密
     *
     * @param content
     * @param password
     * @return
     */
    public static String decrypt256FromString(String content, String password) {
        return decrypt(Base64.decodeBase64(content), password, 256);
    }

    /**
     * 从16进制内容中解密
     *
     * @param hexContent 16进制的加密内容
     * @param password   密码
     * @return
     */
    public static String decrypt256FromHex(String hexContent, String password) {
        return decrypt(parseHexStr2Byte(hexContent), password, 256);
    }

    /**
     * 从base64标示的加密字符串中解密
     *
     * @param content
     * @param password
     * @return
     */
    public static String decryptFromString(String content, String password) {
        return decrypt(Base64.decodeBase64(content), password, 128);
    }

    /**
     * 从16进制内容中解密
     *
     * @param hexContent 16进制的加密内容
     * @param password   密码
     * @return
     */
    public static String decryptFromHex(String hexContent, String password) {
        return decrypt(parseHexStr2Byte(hexContent), password, 128);
    }

    /**
     * 将二进制转换成16进制
     *
     * @param buf
     * @return
     */
    public static String parseByte2HexStr(byte buf[]) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < buf.length; i++) {
            String hex = Integer.toHexString(buf[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString();
    }

    /**
     * 将16进制转换为二进制
     *
     * @param hexStr
     * @return
     */
    public static byte[] parseHexStr2Byte(String hexStr) {
        if (hexStr.length() < 1) {
            return null;
        }
        byte[] result = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / 2; i++) {
            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }

    public static OkHttpClient client;
    public static String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCzr4T+4bnyYnamk2CPuhU08CyttEnuaYr7hSC1jZvL+i1o9l66wRCeP9z5GonsT6kH9hN0KBnJEfsgYvv9yDi0qSk4qYqMOPimlWRELMcqNw9UXihL3mmvdKio+Q+Y7lyx51kDR3a0TWfkMkgrif4HsUqQNCKDJ04+6oo0+BorcQIDAQAB";
    public static String phone = "18686652665";
    public static String user_id = "1078224583295872";
    public static String union_id = "210000511078224583295872";
    public static String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI5YjlkOTJkNC00M2UyLTQ2ZmYtOTEyOC02YWIwZjFjOGRiM2QiLCJpc3MiOiJZYW5ZYW4iLCJzdWIiOiJ7XCJ1c2VySWRcIjpcIjEwNzgyMjQ1ODMyOTU4NzJcIixcInVuaW9uSWRcIjpcIjIxMDAwMDUxMTA3ODIyNDU4MzI5NTg3MlwiLFwib3BlbmFwaWFjY291bnRcIjpcIjEwNzgyMjQ1ODMyOTU4NzJcIixcIm5ld0RldmljZUlkXCI6bnVsbCxcIm5ld0RldmljZVR5cGVcIjpcIm51bGxcIn0iLCJpYXQiOjE3NDkwODk2MzAsImV4cCI6MTc1MTY4MTYzMH0.gK8WU-pG2MLT7yGIVeWxqeur2II7HpjUsQBCf2rtRog";
    public static String url = "https://dev.bwton.cn/bmp-dev-cc01";
    public static MediaType JSON = MediaType.parse("application/json; charset=utf-8");
    public static Gson gson = new Gson();
    public static String deviceInfo = "{\"appVersion\":\"1.0.5\",\"appName\":\"长春E出行\",\"latitude\":\"\",\"imsi\":\"\",\"usedDisk\":\"85454\",\"systemVersion\":\"New Version:29\",\"appVersionCode\":\"49\",\"totalDisk\":\"230871\",\"city_name\":\"长春\",\"macAddress\":\"A8:9C:ED:B3:BE:16\",\"mobileBrand\":\"Xiaomi\",\"sourceIp\":\"fe80::b070:6aff:febd:e507%dummy0\",\"sourceType\":\"1\",\"imei\":\"00000000-2ab4-a945-ffff-ffffcbe41f7b\",\"longitude\":\"\"}";
    private static final String CHAR_AND_NUM = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    public static String VI = generateRandomString(16);
    public static String KEY = generateRandomString(16);

    public static void doPost(String path, String json) throws Exception {
        RequestBody body = RequestBody.create(JSON, json);

        String sequence = SequenceUtil.genSequence();
        System.out.println("seq:"+sequence);
        String version = "0400";
        String nonce = generateRandomString(20);
        String timestamp = new Date().getTime() + "";
        String appid = "A320420190100001";
        String merchantId = "320420240702";
        String placeCode = "21000051";
        boolean needRandom = true;
        String random = "AES/CBC:" + VI + "," + KEY;
        String signStr = "appid=" + appid +
                "&message=" + json +
                "&nonce=" + nonce;
        String encryptedRandom = RSA2Utils.encryptByPublicKey(random, publicKey);
        if (needRandom) {
            signStr += "&random=" + encryptedRandom;
        }
        signStr += "&sequence=" + sequence +
                "&timestamp=" + timestamp +
                "&version=" + version;
        String digest = DigestUtils.sha256Hex(signStr.getBytes(StandardCharsets.UTF_8));
        String signature = RSA2Utils.encryptByPublicKey(digest, publicKey);

        final Request request = new Request.Builder()
                .addHeader("version", version)
                .addHeader("nonce", nonce)
                .addHeader("timestamp", timestamp)
                .addHeader("token", token)
                .addHeader("unionId", union_id)
                .addHeader("appid", appid)
                .addHeader("cityId", "2201")
                .addHeader("random", encryptedRandom)
                .addHeader("sequence", sequence)
                .addHeader("signature", signature)
                .addHeader("merchantId", merchantId)
                .addHeader("placeCode", placeCode)
                .post(body)
                .url(url + path)
                .build();
    }

    public static String generateRandomString(int length) {
        StringBuilder sb = new StringBuilder(length);
        Random random = new Random();

        // 循环生成每个字符
        for (int i = 0; i < length; i++) {
            int index = random.nextInt(CHAR_AND_NUM.length());
            sb.append(CHAR_AND_NUM.charAt(index));
        }
        return sb.toString();
    }
}
